﻿// Copyright 2006 - Ricardo Stuven (rstuven@gmail.com)
//
// This file is part of MsSqlSpatial.
// MsSqlSpatial is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// MsSqlSpatial is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public License
// along with MsSqlSpatial; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 

using System;
using System.Collections;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using GeoAPI.Geometries;
using MsSqlSpatial;

public partial class TableValuedFunctions
{
    public static void FillRowSpatialQuery(Object obj, out SqlInt64 oid)
    {
        oid = new SqlInt64((Int64) obj);
    }

    #region Nested type: SpatialQuery

    private class SpatialQuery
    {
        internal const string FillRow = "FillRowSpatialQuery";
        internal const string TableDefinition = "oid bigint";

        internal static IEnumerable Execute(
            SqlString table_name,
            SqlString column_name,
            SqlBytes ewkbMBR,
            ReaderHandler handler)
        {
            return Execute(table_name, column_name, ewkbMBR, null, SqlString.Null, Arguments.Empty, handler);
        }

        internal static IEnumerable Execute(
            SqlString table_name,
            SqlString column_name,
            SqlBytes ewkbMBR,
            SqlString condition,
            ReaderHandler handler)
        {
            return Execute(table_name, column_name, ewkbMBR, null, condition, Arguments.Empty, handler);
        }

        internal static IEnumerable Execute(
            SqlString table_name,
            SqlString column_name,
            SqlBytes ewkbMBR,
            Arguments args,
            ReaderHandler handler)
        {
            return Execute(table_name, column_name, ewkbMBR, null, SqlString.Null, args, handler);
        }

        internal static IEnumerable Execute(
            SqlString table_name,
            SqlString column_name,
            SqlBytes ewkbMBR,
            SqlString condition,
            Arguments args,
            ReaderHandler handler)
        {
            return Execute(table_name, column_name, ewkbMBR, null, condition, args, handler);
        }


        internal static IEnumerable Execute(
            SqlString table_name,
            SqlString column_name,
            SqlBytes ewkbMBR,
            SqlBytes ewkb,
            Arguments args,
            ReaderHandler handler)
        {
            return Execute(table_name, column_name, ewkbMBR, ewkb, SqlString.Null, args, handler);
        }

        internal static IEnumerable Execute(
            SqlString table_name,
            SqlString column_name,
            SqlBytes ewkbMBR,
            SqlBytes ewkb,
            SqlString condition,
            Arguments args,
            ReaderHandler handler)
        {
            if (ewkbMBR == null || ewkbMBR.IsNull)
                ewkbMBR = ewkb;

            IGeometry geometryMBR = ConvertGeometry.ToGeometry(ewkbMBR);

            IGeometry geometry;
            if (ewkb == null || ewkb.IsNull)
                geometry = geometryMBR;
            else
                geometry = ConvertGeometry.ToGeometry(ewkb);

            using (SqlConnection connection = DatabaseHelper.ContextConnection)
            {
                connection.Open();
                using (SqlCommand command = connection.CreateCommand())
                {
                    string tableName = table_name.Value;
                    string columnName = column_name.Value;

                    string schemaName = "";
                    DatabaseHelper.SplitSchemaAndTableName(command, ref tableName, ref schemaName);

                    string primaryKey = GeometryTable.GetPrimaryKeyColumn(command, schemaName, tableName);

                    string filterQuery = "";

                    if (geometryMBR != null && !geometryMBR.IsEmpty)
                    {
                        if (!condition.IsNull && condition.Value.Trim().Length != 0)
                            filterQuery = " AND (" + condition.Value + ")";
                        IEnvelope mbr = geometryMBR.EnvelopeInternal;
                        DatabaseHelper.BuildCommand(command, string.Format(
                                                                 @"SELECT [{4}], [{2}]
FROM [{0}].[{1}] WITH (INDEX(IDX_{2}_Envelope))
WHERE 
(   [{2}_Envelope_MinX] < @p0
AND [{2}_Envelope_MaxX] > @p1
AND [{2}_Envelope_MinY] < @p2
AND [{2}_Envelope_MaxY] > @p3
){3}"
                                                                 , schemaName // {0}
                                                                 , tableName // {1}
                                                                 , columnName // {2}
                                                                 , filterQuery // {3}
                                                                 , primaryKey // {4}
                                                                 )
                                                    , mbr.MaxX
                                                    , mbr.MinX
                                                    , mbr.MaxY
                                                    , mbr.MinY
                            );
                    }
                    else
                    {
                        if (!condition.IsNull && condition.Value.Trim().Length != 0)
                            filterQuery = "WHERE " + condition.Value;
                        DatabaseHelper.BuildCommand(command, string.Format(
                                                                 @"SELECT [{4}], [{2}]
FROM [{0}].[{1}]
{3}"
                                                                 , schemaName // {0}
                                                                 , tableName // {1}
                                                                 , columnName // {2}
                                                                 , filterQuery // {3}
                                                                 , primaryKey // {4}
                                                                 ));
                    }

                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        return handler.Invoke(reader, geometry, args);
                    }
                }
            }
        }

        #region Nested type: Arguments

        internal struct Arguments
        {
            public SqlDouble double1;
            public SqlString string1;

            public Arguments(SqlDouble _double1)
            {
                double1 = _double1;
                string1 = SqlString.Null;
            }

            public Arguments(SqlString _string1)
            {
                string1 = _string1;
                double1 = SqlDouble.Null;
            }

            public static Arguments Empty
            {
                get
                {
                    Arguments args;
                    args.double1 = SqlDouble.Null;
                    args.string1 = SqlString.Null;
                    return args;
                }
            }

//
//			public bool IsEmpty
//			{
//			    get { return double1.IsNull && string1.IsNull; }
//			}
        }

        #endregion

        #region Nested type: ReaderHandler

        internal delegate IEnumerable ReaderHandler(SqlDataReader reader, IGeometry geometry, Arguments args);

        #endregion
    }

    #endregion
}